﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.IO;

namespace TiebaSpider.Core
{
    public class ThreadAnalysiser
    {
        private Crawler crawler;
        private bool captureSign;

        public string ThreadID { get; set; }
        public bool OnlyOwner { get; set; }
		public bool Partition { get; set; }
		public Tuple<int, int> SelectedPartition { get; set; }
        public ObservableCollection<Beans.ImageInformation> AllImages { get; set; }
		public String DownloadDirectory { get; set; }

        public event EventHandler<ThreadAnalysiserEventArgs> AnalysisComplete;
        public event EventHandler<ThreadAnalysiserEventArgs> PageAnalysisComplete;
		public event EventHandler<ThreadAnalysiserEventArgs> PartitionSet;

        public ThreadAnalysiser()
        {
            crawler = new Crawler();
            crawler.CrawlerEvent += OnThreadCapture;
            PageAnalysisComplete += OnThreadPageCapture;
            OnlyOwner = false;
            captureSign = false;
			Partition = false;
            AllImages = new ObservableCollection<Beans.ImageInformation>();
			SelectedPartition = new Tuple<int, int>(0, 0);
			DownloadDirectory = "";
        }

        public ThreadAnalysiser(string tid)
            : this()
        {
            ThreadID = tid;
        }

        public ThreadAnalysiser(string tid, bool only)
            : this(tid)
        {
            OnlyOwner = only;
        }

		public ThreadAnalysiser(string tid, bool only, bool partition)
			: this(tid, only)
		{
			Partition = partition;
		}

		public ThreadAnalysiser(String tid, bool only, bool partition, Tuple<int, int> selected)
			: this(tid, only, partition)
		{
			SelectedPartition = selected;
		}

        public void OnThreadCapture(object sender, CrawlerEventArgs e)
        {
            captureSign = true;
        }

        public void OnThreadPageCapture(object sender, ThreadAnalysiserEventArgs e)
        {
            foreach (Beans.ImageInformation image in e.ThreadInfo.ThreadImages)
            {
                AllImages.Add(image);
            }
            if ((Partition && e.ThreadInfo.ReqPage < SelectedPartition.Item2) || 
				(!Partition && e.ThreadInfo.ReqPage < e.ThreadInfo.TotalPage))
            {
                e.ThreadInfo.ReqPage++;
                captureThreadPage(e.ThreadInfo);
            }
            else
            {
                if (AnalysisComplete != null)
                {
                    Beans.ThreadInformation finalInfo = new Beans.ThreadInformation();
                    finalInfo.TID = e.ThreadInfo.TID;
					finalInfo.Partition = e.ThreadInfo.Partition;
                    finalInfo.TotalPage = e.ThreadInfo.TotalPage;
					finalInfo.currentPartition = e.ThreadInfo.currentPartition;
                    finalInfo.ThreadImages = AllImages;
                    AnalysisComplete(this, new ThreadAnalysiserEventArgs(finalInfo));
                }
            }
        }

        public void ThreadCapture()
        {
            Beans.ThreadInformation tInfo = new Beans.ThreadInformation();
            tInfo.TID = ThreadID;
			if (Partition && SelectedPartition.Item2 != 0)
			{
				tInfo.ReqPage = SelectedPartition.Item1;
			}
            captureThreadPage(tInfo);
        }

        private async void captureThreadPage(Beans.ThreadInformation threadInfo)
        {
            ObservableCollection<Beans.ImageInformation> pageImages = new ObservableCollection<Beans.ImageInformation>();
            crawler.TargetURL = OnlyOwner ? string.Format(Beans.AnalysisExpressions.ThreadPagingUrlOnlyOwner, ThreadID, threadInfo.ReqPage)
                : string.Format(Beans.AnalysisExpressions.ThreadPagingUrlNormal, ThreadID, threadInfo.ReqPage);
            captureSign = false;
            string pageContent = await crawler.GetStringContent();
            while (!captureSign) { }
            if (!pageContent.Equals(string.Empty))
            {
				if (threadInfo.ReqPage == 1 || (Partition && SelectedPartition.Item2 != 0))
                {
                    MatchCollection pageMatches = Regex.Matches(pageContent, Beans.AnalysisExpressions.ThreadPagingDetection);
                    foreach (Match match in pageMatches)
                    {
                        int detPage = int.Parse(match.Groups[1].Value);
                        if (detPage > threadInfo.TotalPage) threadInfo.TotalPage = detPage;
                    }
					if (Partition && SelectedPartition.Item2==0)
					{
						threadInfo.Partition = Partition;
						SelectedPartition = threadInfo.PagePartition[0];
						threadInfo.currentPartition = SelectedPartition;
						PartitionSet(this, new ThreadAnalysiserEventArgs(threadInfo));
					}
                }
                MatchCollection matches = Regex.Matches(pageContent, Beans.AnalysisExpressions.PictureCaptureFromThread, RegexOptions.IgnoreCase);
                foreach (Match match in matches)
				{
					Beans.ImageInformation image = new Beans.ImageInformation();
					image.ThumbnailUrl = match.Groups[1].Value;
					if (!DownloadDirectory.Length.Equals(0))
					{
						if (Directory.Exists(DownloadDirectory))
						{
							String fileName = DownloadDirectory + Path.DirectorySeparatorChar + image.Name;
							if (File.Exists(fileName)) continue;
						}
					}
                    pageImages.Add(image);
                }
            }
            if (PageAnalysisComplete != null)
            {
				threadInfo.Partition = Partition;
                threadInfo.ThreadImages = pageImages;
				threadInfo.currentPartition = SelectedPartition;
                PageAnalysisComplete(this, new ThreadAnalysiserEventArgs(threadInfo));
            }
        }
    }

    public class ThreadAnalysiserEventArgs : EventArgs
    {
        public Beans.ThreadInformation ThreadInfo { get; set; }

        public ThreadAnalysiserEventArgs(Beans.ThreadInformation info)
        {
            ThreadInfo = info;
        }
    }
}
